package com.vhall.component.service.vote.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vhall.component.dao.account.AccountMapper;
import com.vhall.component.dao.vote.RoomVoteLkMapper;
import com.vhall.component.dao.vote.VoteAnswersMapper;
import com.vhall.component.dao.vote.VoteOptionCountMapper;
import com.vhall.component.dao.vote.VotesMapper;
import com.vhall.component.entity.account.AccountEntity;
import com.vhall.component.entity.page.vo.PageVO;
import com.vhall.component.entity.room.dto.RoomJoinsEntityDTO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.entity.vote.RoomVoteLkEntity;
import com.vhall.component.entity.vote.VoteAnswersEntity;
import com.vhall.component.entity.vote.VoteOptionCountEntity;
import com.vhall.component.entity.vote.VotesEntity;
import com.vhall.component.entity.vote.vo.*;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.constant.RoomConstant;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.support.VssToken;
import com.vhall.component.plugin.common.support.VssTokenThreadLocal;
import com.vhall.component.plugin.common.utils.DateUtils;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.service.room.RoomInnerService;
import com.vhall.component.service.vote.VoteConstants;
import com.vhall.component.service.vote.VoteService;
import com.vhall.component.service.vote.VotesRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author longzhen.gong
 * @date 2021/7/6 11:53
 */
@Service
@Slf4j
public class VoteServiceImpl implements VoteService {


    @Autowired
    private VotesMapper votesMapper;

    @Autowired
    private VotesRepository votesRepository;

    @Autowired
    private RoomInnerService roomInnerFacade;


    @Autowired
    private RoomVoteLkMapper roomVoteLkMapper;

    @Autowired
    private VoteOptionCountMapper voteOptionCountMapper;

    @Autowired
    private PaasService paasService;

    @Autowired
    private VoteAnswersMapper voteAnswersMapper;


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RoomInnerService roomInnerService;
    @Autowired
    private AccountMapper accountMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public VotesCreateRspVO create(VotesCreateReqVO reqVO) {
        RoomJoinsEntityDTO roomJoinsEntityDTO = roomInnerService.getRoomJoins(reqVO.getAccountId(), reqVO.getRoomId());
        if (roomJoinsEntityDTO == null
                || roomJoinsEntityDTO.getRoleName().equals(RoomConstant.AUDIENCE)) {
            throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
        }
        Long voteId = reqVO.getVoteId();
        if (votesRepository.getById(voteId) != null) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
        }
        try {
            JSON.parseArray(reqVO.getExtend());
        } catch (Exception e) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_EXTEND);
        }
        RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(reqVO.getRoomId());
        //缺少与sdk保持数据一致的校验
        VotesEntity votesEntity = new VotesEntity();
        votesEntity.setAccountId(roomInfo.getAccountId());
        votesEntity.setVoteId(reqVO.getVoteId());
        votesEntity.setExtend(reqVO.getExtend());
        votesEntity.setIsPublic(VoteConstants.RoomVoteLkBind.PUBLIC_YES);
        votesEntity.setLimitTime(reqVO.getLimitTime());
        votesEntity.setOptionNum(reqVO.getOptionNum());
        votesEntity.setTitle(reqVO.getTitle());
        votesEntity.setCreatedAt(LocalDateTime.now());
        votesEntity.setUpdatedAt(LocalDateTime.now());
        votesRepository.save(votesEntity);
        votesEntity = votesRepository.getById(voteId);
        if (StringUtils.isNotBlank(reqVO.getRoomId())) {
            bindRoom(voteId, reqVO.getRoomId());
        }
        VotesCreateRspVO createRspVO = new VotesCreateRspVO();
        BeanUtils.copyProperties(votesEntity, createRspVO);
        return createRspVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public VotesUpdateRspVO update(VotesUpdateRepVO reqVO) {
        Long voteId = reqVO.getVoteId();
        VotesEntity votesEntity = votesRepository.getById(voteId);
        if (votesEntity == null) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
        }
        try {
            JSON.parseArray(reqVO.getExtend());
        } catch (Exception e) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_EXTEND);
        }
        if (StringUtils.isNotBlank(reqVO.getRoomId())) {
            RoomsEntityDTO roomsEntityDTO = roomInnerFacade.getRoomInfo(reqVO.getRoomId());
            if (roomsEntityDTO == null) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
            }
        }

        List<RoomVoteLkEntity> roomVoteLkEntities = roomVoteLkMapper.selectList(Wrappers.<RoomVoteLkEntity>lambdaQuery()
                .eq(RoomVoteLkEntity::getVoteId, voteId));
        if (CollectionUtils.isNotEmpty(roomVoteLkEntities) && roomVoteLkEntities.size() > 1) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_BIND_REPEAT);
        }
        RoomVoteLkEntity roomVoteLkEntity = null;
        if (CollectionUtils.isNotEmpty(roomVoteLkEntities)) {
            roomVoteLkEntity = roomVoteLkEntities.get(0);
            if (VoteConstants.RoomVoteLkBind.PUBLISH_YES == roomVoteLkEntity.getPublish()) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_PUBLISHED_NOT_EDIT);
            }
        }

        if (StringUtils.isNotBlank(reqVO.getRoomId())) {
            if (CollectionUtils.isEmpty(roomVoteLkEntities)) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
            }
            if (roomVoteLkEntity == null) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
            }
            if (!reqVO.getRoomId().equals(roomVoteLkEntity.getRoomId())) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
            }

            //rvlk_id对应选项删除
            redisTemplate.expire(RedisKey.VOTE_RVLK + roomVoteLkEntity.getId(), 0, TimeUnit.SECONDS);

            voteOptionCountMapper.delete(Wrappers.<VoteOptionCountEntity>lambdaQuery()
                    .eq(VoteOptionCountEntity::getRvlkId, roomVoteLkEntity.getId()));

            voteOptionCountCreate(voteId, roomVoteLkEntity.getId());

            if (!StringUtils.equalsAnyIgnoreCase(roomVoteLkEntity.getRoomId(), reqVO.getRoomId())) {
                roomVoteLkEntity.setRoomId(reqVO.getRoomId());
                roomVoteLkEntity.setUpdatedAt(LocalDateTime.now());
                roomVoteLkMapper.updateById(roomVoteLkEntity);
            }
        }

        BeanUtils.copyProperties(reqVO, votesEntity);
        votesEntity.setUpdatedAt(LocalDateTime.now());
        votesEntity.setAccountId(null);
        votesMapper.updateById(votesEntity);
        VotesUpdateRspVO votesUpdateRspVO = new VotesUpdateRspVO();
        BeanUtils.copyProperties(votesEntity, votesUpdateRspVO);
        return votesUpdateRspVO;
    }

    @Override
    public PageVO<VotesListRspVO> list(VotesListReqVO reqVO) {
        List<VotesListRspVO> votesListRspVos;
        int curPage = reqVO.getPage() == null ? 1 : reqVO.getPage();
        int pageSize = reqVO.getPagesize() == null ? 10 : reqVO.getPagesize();
        reqVO.setPage(curPage);
        reqVO.setPagesize(pageSize);
        if (StringUtils.isEmpty(reqVO.getRoomId())){
            reqVO.setAccountId(null);
            Token token = TokenThreadLocal.getToken();
            if (token.getRoleType() != null && token.getRoleType() == 2) {
                LambdaQueryWrapper<AccountEntity> queryWrapper = Wrappers.lambdaQuery();
                queryWrapper.eq(AccountEntity::getOrgCode, token.getOrgCode());
                List<AccountEntity> accountEntities = accountMapper.selectList(queryWrapper);
                List<Integer> accountIds = accountEntities.stream().map(AccountEntity::getAccountId).collect(Collectors.toList());
                reqVO.setAccountIds(accountIds);
            }
        }

        if (StringUtils.isNotEmpty(reqVO.getRoomId())){
            RoomJoinsEntityDTO roomJoinsEntityDTO = roomInnerService.getRoomJoins(Integer.parseInt(reqVO.getAccountId()), reqVO.getRoomId());
            if (roomJoinsEntityDTO == null
                    || roomJoinsEntityDTO.getRoleName().equals(RoomConstant.AUDIENCE)) {
                throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
            }
        }
        reqVO.setAccountId(null);
        int count = votesMapper.listCount(reqVO);
        votesListRspVos = votesMapper.list(reqVO);
        // 发布时间
        if (reqVO.getPublish() != null) {
            votesListRspVos = votesListRspVos.stream().map(r -> {
                int second = (int) r.getFinishTime().toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
                String publishTime = DateUtils.timestampFormat(second, r.getLimitTime());
                r.setPublishTime(publishTime);
                return r;
            }).collect(Collectors.toList());
        }
        // 查询是否回答过问卷
        if (reqVO.getAnswerAccountId() != null) {
            RoomJoinsEntityDTO roomJoinInfo = roomInnerFacade.getRoomJoinInfo(reqVO.getAnswerAccountId(), reqVO.getRoomId());
            List<Long> voteIdList = votesListRspVos.stream().map(VotesListRspVO::getVoteId).collect(Collectors.toList());
            LambdaQueryWrapper<VoteAnswersEntity> where = Wrappers.lambdaQuery();
            where.eq(VoteAnswersEntity::getRoomId, reqVO.getRoomId())
                    .eq(VoteAnswersEntity::getJoinId, roomJoinInfo.getJoinId())
                    .in(!voteIdList.isEmpty(), VoteAnswersEntity::getVoteId, voteIdList);
            List<VoteAnswersEntity> answersList = voteAnswersMapper.selectList(where);
            Map<Long, VoteAnswersEntity> answerMap = answersList.stream().collect(Collectors.toMap(VoteAnswersEntity::getVoteId, alk -> alk));
            votesListRspVos = votesListRspVos.stream().map(r -> {
                Integer answer = answerMap.get(r.getVoteId()) == null ? 0 : 1;
                Integer answerId = answerMap.get(r.getVoteId()) == null ? 0 : Math.toIntExact(answerMap.get(r.getVoteId()).getAnswerId());
                r.setAnswer(answer);
                r.setAnswerId(answerId);
                return r;
            }).collect(Collectors.toList());
        }
        if (StringUtils.isNotBlank(reqVO.getFromRoomId()) && votesListRspVos != null) {
            List<Long> voteIdList = votesListRspVos.stream().map(VotesListRspVO::getVoteId).collect(Collectors.toList());
            LambdaQueryWrapper<RoomVoteLkEntity> where = Wrappers.lambdaQuery();
            where.eq(RoomVoteLkEntity::getRoomId, reqVO.getFromRoomId())
                    .in(!voteIdList.isEmpty(), RoomVoteLkEntity::getVoteId, voteIdList);
            List<RoomVoteLkEntity> lkList = roomVoteLkMapper.selectList(where);
            Map<Long, RoomVoteLkEntity> lkMap = lkList.stream().collect(Collectors.toMap(RoomVoteLkEntity::getVoteId, lk -> lk));
            votesListRspVos = votesListRspVos.stream().map(r -> {
                Integer publish = lkMap.get(r.getVoteId()) == null ? 0 : lkMap.get(r.getVoteId()).getPublish();
                Integer bind = lkMap.get(r.getVoteId()) == null ? 0 : lkMap.get(r.getVoteId()).getBind();
                Integer answer = lkMap.get(r.getVoteId()) == null ? 0 : 1;
                r.setPublish(publish);
                r.setBind(bind);
                r.setAnswer(answer);
                return r;
            }).collect(Collectors.toList());
        }
        if (votesListRspVos == null) {
            return new PageVO<>(curPage, 0, count, null);
        }
        return new PageVO<>(curPage, votesListRspVos.size(), count, votesListRspVos);
    }

    /**
     * 当前账号是否回答过这个问题
     *
     * @param accountId
     * @param reqVO
     * @param accountId
     * @return
     */
    @Override
    public VoteInfoRspVO info(VoteInfoReqVO reqVO, Integer accountId) {
        VoteInfoRspVO voteInfoRspVO = new VoteInfoRspVO();
        if (StringUtils.isBlank(reqVO.getRoomId())) {
            VotesEntity votesEntity = votesMapper.selectById(reqVO.getVoteId());
            BeanUtils.copyProperties(votesEntity, voteInfoRspVO);
        } else {
            RoomVoteLkEntity roomVoteLkEntity = roomVoteLkMapper.selectOne(Wrappers.<RoomVoteLkEntity>lambdaQuery()
                    .eq(RoomVoteLkEntity::getRoomId, reqVO.getRoomId())
                    .eq(RoomVoteLkEntity::getVoteId, reqVO.getVoteId()));
            if (roomVoteLkEntity == null) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
            }
            BeanUtils.copyProperties(roomVoteLkEntity, voteInfoRspVO);
            voteInfoRspVO.setCurrentTime(LocalDateTime.now());

            Long remainTime = null;
            if (roomVoteLkEntity.getFinishTime() != null) {
                remainTime = Math.max(ChronoUnit.SECONDS.between(LocalDateTime.now(), roomVoteLkEntity.getFinishTime()), 0);
            }

            voteInfoRspVO.setRemainTime(remainTime);
        }
        boolean existAnswer = voteAnswersMapper.selectCount(Wrappers.<VoteAnswersEntity>lambdaQuery()
                .eq(VoteAnswersEntity::getVoteId, reqVO.getVoteId())
                .eq(VoteAnswersEntity::getAccountId, accountId)) > 0;
        voteInfoRspVO.setAnswer(existAnswer ? 1 : 0);
        return voteInfoRspVO;

    }

    @Override
    public List<VoteDetailRspVO> voteDetail(VoteDetailReqVO reqVO, Integer accountId) {
        String roomId = reqVO.getRoomId();
        Long voteId = reqVO.getVoteId();
        RoomsEntityDTO roomsEntityDTO = roomInnerFacade.getRoomInfo(roomId);
        if (roomsEntityDTO == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        VotesEntity votesEntity = votesMapper.selectById(reqVO.getVoteId());
        if (votesEntity == null) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_NOT_EXIST);
        }
        RoomVoteLkEntity roomVoteLkEntity = roomVoteLkMapper.selectOne(Wrappers.<RoomVoteLkEntity>lambdaQuery()
                .eq(RoomVoteLkEntity::getRoomId, roomId)
                .eq(RoomVoteLkEntity::getVoteId, voteId));
        if (roomVoteLkEntity == null) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
        }
        if (ObjectUtils.notEqual(roomVoteLkEntity.getPublish(), VoteConstants.RoomVoteLkBind.PUBLISH_YES)) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_NOT_PUBLISH);
        }
        List<VoteOptionCountEntity> voteOptionCounts = getVoteOptionCountInfoByRvlkId(roomVoteLkEntity.getId());
        if (CollectionUtils.isEmpty(voteOptionCounts)) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
        }
        Map<String, JSONObject> userVote = new HashMap<>(16);
        //投票用户查看详情
        if (reqVO.getAccountId() != null) {
            if (ObjectUtils.notEqual(reqVO.getAccountId(), accountId)) {
                throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
            }
            RoomJoinsEntityDTO roomJoinsEntityDTO = roomInnerFacade.getRoomJoins(accountId, roomId);
            if (roomJoinsEntityDTO == null) {
                throw new BusinessException(BizErrorCode.BIZ_NO_PERMISSION);
            }
            VoteAnswersEntity voteAnswersEntitie = voteAnswersMapper.selectOne(Wrappers.<VoteAnswersEntity>lambdaQuery()
                    .eq(VoteAnswersEntity::getVoteId, reqVO.getVoteId())
                    .eq(VoteAnswersEntity::getJoinId, roomJoinsEntityDTO.getJoinId())
                    .eq(VoteAnswersEntity::getRoomId, roomId));
            if (voteAnswersEntitie != null) {
                String extend = voteAnswersEntitie.getExtend();
                JSONArray jsonArray = JSON.parseArray(extend);
                for (Object obj : jsonArray) {
                    userVote.put(((JSONObject) obj).getString("id"), (JSONObject) obj);
                }
            }
        }

        Map<String, Map<String, Object>> voteQuestions = new HashMap<>(16);
        String titleKey = "title";
        String descriptionKey = "description";
        String imgUrlKey = "imgUrl";
        String valueKey = "value";

            JSONObject formInfo = paasService.getFormInfo(voteId + "");

            String detailKey = "detail";

            if (formInfo.get(detailKey) == null) {
                throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
            }
            JSONArray formDetail = formInfo.getJSONArray(detailKey);
            for (Object questionDetail : formDetail) {
                JSONObject questionDetailJson = (JSONObject) questionDetail;
                Map<String, Object> question = voteQuestions.getOrDefault(questionDetailJson.getString("id"), new HashMap<>(4));
                question.put("question_id", questionDetailJson.getString("id"));
                question.put(titleKey, formInfo.getString(titleKey));
                question.put(descriptionKey, formInfo.getString(descriptionKey));
                question.put(imgUrlKey, questionDetailJson.getString(descriptionKey));
                question.put("type", questionDetailJson.getString("type"));
                voteQuestions.put(questionDetailJson.getString("id"), question);
                JSONArray optionDetails = questionDetailJson.getJSONObject(detailKey).getJSONArray("list");
                Map<String, Map<String, Object>> voteOptions = new HashMap<>(16);
                for (Object optionDetailObj : optionDetails) {
                    JSONObject optionDetailJson = (JSONObject) optionDetailObj;
                    Map<String, Object> voteOption = new HashMap<>(16);
                    voteOption.put("question_id", questionDetailJson.get("id"));
                    voteOption.put("option_id", optionDetailJson.get("id"));
                    voteOption.put("key", optionDetailJson.getString("key"));
                    voteOption.put(valueKey, optionDetailJson.getString(valueKey));
                    voteOptions.put(optionDetailJson.getString("id"), voteOption);
                }
                question.put("list", voteOptions);
            }

        List<VoteDetailRspVO> voteDetailRspVos = new ArrayList<>();
        for (VoteOptionCountEntity voteOptionCountEntity : voteOptionCounts) {
            Map<String, Object> question = voteQuestions.getOrDefault(String.valueOf(voteOptionCountEntity.getQuestionId()), new HashMap<>(16));
            Optional<VoteDetailRspVO> voteDetailRspVoOptional = voteDetailRspVos.stream().filter(x -> x.getQuestionId().compareTo(voteOptionCountEntity.getQuestionId()) == 0).findFirst();
            VoteDetailRspVO voteDetailRspVo;
            if (!voteDetailRspVoOptional.isPresent()) {
                voteDetailRspVo = new VoteDetailRspVO();
                voteDetailRspVo.setQuestionId(voteOptionCountEntity.getQuestionId());
                voteDetailRspVo.setTitle((String) question.getOrDefault(titleKey, ""));
                voteDetailRspVo.setDescription((String) question.getOrDefault(descriptionKey, ""));
                voteDetailRspVo.setImgUrl((String) question.getOrDefault(imgUrlKey, ""));
                voteDetailRspVo.setType((String) question.getOrDefault("type", ""));
                voteDetailRspVo.setExtend(votesEntity.getExtend());
                voteDetailRspVos.add(voteDetailRspVo);
            } else {
                voteDetailRspVo = voteDetailRspVoOptional.get();
            }

            Map<String, VoteDetailRspVO.Option> options = voteDetailRspVo.getList();
            if (options == null) {
                options = new HashMap<>(16);
                voteDetailRspVo.setList(options);
            }

            VoteDetailRspVO.Option option = options.getOrDefault(voteOptionCountEntity.getOption(), new VoteDetailRspVO.Option());
            options.put(voteOptionCountEntity.getOption(), option);
            option.setOption(voteOptionCountEntity.getOption());
            option.setOptionId(voteOptionCountEntity.getOptionId());
            option.setCount(voteOptionCountEntity.getCount());
            option.setValue("");
            option.setAnswer(0);
            JSONObject userVoteJson = userVote.get(String.valueOf(voteOptionCountEntity.getQuestionId()));
            if (userVoteJson != null && "radio".equalsIgnoreCase(userVoteJson.getString("type")) &&
                    userVoteJson.getString("replys").equalsIgnoreCase(option.getOption())) {
                option.setAnswer(1);
            }
//            log.info("临时日志，{}", userVoteJson.toJSONString());
//            if (userVoteJson != null && "radio".equalsIgnoreCase(userVoteJson.getString("type"))) {
//                JSONArray replys = userVoteJson.getJSONArray("replys");
//                if (replys.equals(option.getOption())) {
//                    option.setAnswer(1);
//                }
//            }
            if (userVoteJson != null && "checkbox".equalsIgnoreCase(userVoteJson.getString("type"))) {
                JSONArray replys = userVoteJson.getJSONArray("replys");
                if (replys.contains(option.getOption())) {
                    option.setAnswer(1);
                }
            }
            if (voteQuestions.size() > 0) {
                Map<String, Object> questionDetail = voteQuestions.getOrDefault(voteOptionCountEntity.getQuestionId() + "", new HashMap<>(16));
                voteDetailRspVo.setTitle((String) questionDetail.getOrDefault(titleKey, ""));
                voteDetailRspVo.setDescription((String) questionDetail.getOrDefault(descriptionKey, ""));
                voteDetailRspVo.setImgUrl((String) questionDetail.getOrDefault(imgUrlKey, ""));
                voteDetailRspVo.setType((String) questionDetail.getOrDefault("type", ""));
                Map<String, Object> optionsDetails = (Map<String, Object>) questionDetail.get("list");
                Map<String, Object> optionDetail = (Map<String, Object>) optionsDetails.getOrDefault(option.getOptionId() + "", new HashMap<>(16));
                option.setValue((String) optionDetail.getOrDefault(valueKey, ""));
            }
        }
        return voteDetailRspVos;
    }

    @Override
    public String answerCreate(String client, String id, String answer) {
        Map<String, Object> param = new HashMap<>();
        VssToken token = VssTokenThreadLocal.getToken();
        param.put("id", id);
        param.put("client", client);
        param.put("answer", answer);
        param.put("third_party_user_id", token.getThirdPartyUserId().toString());
        JSONObject jsonObject = paasService.answerCreate(param);
        return jsonObject.getString("id");
    }

    /**
     * 获取房间下投票选项计数信息
     *
     * @param rvlkId
     * @return
     */
    @Override
    public List<VoteOptionCountEntity> getVoteOptionCountInfoByRvlkId(Long rvlkId) {
        boolean flag = true;
        String key = RedisKey.VOTE_RVLK + rvlkId;
        long ttl = redisTemplate.opsForValue().getOperations().getExpire(key);
        if (ttl < 10) {
            flag = false;
        }
        Map<Object, Object> optionsMap = new HashMap<>(16);
        if (flag) {
            optionsMap = stringRedisTemplate.opsForHash().entries(key);
        }
        List<VoteOptionCountEntity> optionList = new ArrayList<>();
        if (optionsMap.size() > 0) {
            for (Map.Entry<Object, Object> entry : optionsMap.entrySet()) {
                String questionId = (String) entry.getKey();
                String question = (String) entry.getValue();
                JSONArray jsonArray = JSON.parseArray(question);
                for (Object option : jsonArray) {
                    if (Boolean.FALSE.equals(stringRedisTemplate.hasKey(RedisKey.VOTE_QUESTION + questionId))) {
                        flag = false;
                        continue;
                    }
                    JSONObject optionJson = (JSONObject) option;
                    String count = (String) stringRedisTemplate.opsForHash().get(RedisKey.VOTE_QUESTION + questionId, optionJson.getString("option"));
                    optionJson.put("count", count);
                    optionList.add(JSON.parseObject(optionJson.toJSONString(), VoteOptionCountEntity.class));
                }
            }
        }
        //无缓存 或 key不存在重新写入缓存
        if (!flag || CollectionUtils.isEmpty(optionList)) {
            optionList = voteOptionCountMapper.selectList(
                    Wrappers.<VoteOptionCountEntity>lambdaQuery()
                            .eq(VoteOptionCountEntity::getRvlkId, rvlkId));

            Map<Long, List<VoteOptionCountEntity>> rvlkData = new HashMap<>(16);
            Map<Long, Map<String, String>> questionData = new HashMap<>(16);

            for (VoteOptionCountEntity option : optionList) {
                List<VoteOptionCountEntity> voteOptionCountEntities = rvlkData.getOrDefault(option.getQuestionId(), new ArrayList<>());
                voteOptionCountEntities.add(option);
                rvlkData.put(option.getQuestionId(), voteOptionCountEntities);

                Map<String, String> opC = questionData.getOrDefault(option.getQuestionId(), new HashMap<>(16));
                opC.put(option.getOption(), option.getCount() + "");
                questionData.put(option.getQuestionId(), opC);
            }

            for (Map.Entry<Long, Map<String, String>> entry : questionData.entrySet()) {
                stringRedisTemplate.opsForHash().putAll(RedisKey.VOTE_QUESTION + entry.getKey(), entry.getValue());
                stringRedisTemplate.expire(RedisKey.VOTE_QUESTION + entry.getKey(), VoteConstants.VOTE_QUESTION_EXPIRE_TIME, TimeUnit.SECONDS);
            }
            for (Map.Entry<Long, List<VoteOptionCountEntity>> entry : rvlkData.entrySet()) {
                List<VoteOptionCountEntity> voteOptionCountEntities = entry.getValue();
                String value = JSON.toJSONString(voteOptionCountEntities);
                stringRedisTemplate.opsForHash().put(RedisKey.VOTE_RVLK + rvlkId, entry.getKey() + "", value);
            }

            stringRedisTemplate.expire(RedisKey.VOTE_RVLK + rvlkId, VoteConstants.VOTE_RVLK_EXPIRE_TIME, TimeUnit.SECONDS);
        }
        return optionList;
    }

    @Override
    public Boolean bindRoom(Long voteId, String roomId) {
        VotesEntity votesEntity = votesRepository.getById(voteId);
        RoomsEntityDTO rooms = roomInnerFacade.getRoomInfo(roomId);
        if (rooms == null) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        if (votesEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_VOTE);
        }
//        if (!Objects.equals(rooms.getAccountId(), votesEntity.getAccountId())) {
//            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
//        }
        RoomVoteLkEntity roomVoteLkEntity = roomVoteLkMapper.selectOne(Wrappers.<RoomVoteLkEntity>lambdaQuery()
                .eq(RoomVoteLkEntity::getRoomId, rooms.getRoomId())
                .eq(RoomVoteLkEntity::getVoteId, votesEntity.getVoteId()));
        if (roomVoteLkEntity == null) {
            roomVoteLkEntity = new RoomVoteLkEntity();
            roomVoteLkEntity.setRoomId(rooms.getRoomId());
            roomVoteLkEntity.setBind(VoteConstants.RoomVoteLkBind.BIND);
            roomVoteLkEntity.setVoteId(voteId);
            roomVoteLkEntity.setAccountId(votesEntity.getAccountId());
            roomVoteLkEntity.setExtend(votesEntity.getExtend());
            roomVoteLkEntity.setPublish(VoteConstants.RoomVoteLkBind.PUBLISH_NO);
            //是否发布评分 0-未发布 1-发布
            roomVoteLkEntity.setIsRelease(VoteConstants.RoomVoteLkBind.UNRELEASE);
            roomVoteLkEntity.setIsFinish(VoteConstants.RoomVoteLkBind.UNFINISH);
            roomVoteLkMapper.insert(roomVoteLkEntity);
            voteOptionCountCreate(voteId, roomVoteLkEntity.getId());
        } else {
            roomVoteLkEntity.setUpdatedAt(LocalDateTime.now());
            roomVoteLkEntity.setBind(VoteConstants.RoomVoteLkBind.BIND);
            roomVoteLkMapper.updateById(roomVoteLkEntity);
        }
        return true;
    }


    /**
     * 投票选项创建
     *
     * @param votesId
     * @param rvlkId
     */
    private void voteOptionCountCreate(Long votesId, Long rvlkId) {
        if (!ObjectUtils.allNotNull(votesId, rvlkId)) {
            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
        }
        JSONObject jsonObject = paasService.getFormInfo(votesId + "");
        String detailKey = "detail";
        JSONArray formDetail = jsonObject.getJSONArray(detailKey);
        if (CollectionUtils.isEmpty(formDetail)) {
            throw new BusinessException(BizErrorCode.COMP_VOTE_INVALID);
        }
        for (Object questionDetail : formDetail) {
            JSONObject qu = (JSONObject) questionDetail;
            JSONArray optionDetails = qu.getJSONObject(detailKey).getJSONArray("list");
            for (Object optionDetailObj : optionDetails) {
                JSONObject optionDetail = (JSONObject) optionDetailObj;
                VoteOptionCountEntity voteOptionCountEntity = new VoteOptionCountEntity();
                voteOptionCountEntity.setRvlkId(rvlkId);
                voteOptionCountEntity.setQuestionId(((JSONObject) questionDetail).getLong("id"));
                voteOptionCountEntity.setOptionId(optionDetail.getLong("id"));
                voteOptionCountEntity.setOption(optionDetail.getString("key"));
                voteOptionCountMapper.insert(voteOptionCountEntity);
            }
        }
    }
}
